# 需要安装的库
# pip install opencv_python
# pip install pillow
# pip install requests

import cv2
import numpy as np
from PIL import Image
from io import BytesIO
import requests
def match_correlation(target, template):
    """
     自定义相关匹配法（该方法采用乘法操作；数值越大表明匹配程度越好）
    :param target:    搜索图
    :param template: 模版图
    :return:
    """

    # 搜索图预处理
    target_canny = preprocess_target(target)
    # 模版图预处理
    template_thresh,contour = preprocess_template(template)

    h, w = target_canny.shape

    template_h,template_w = template_thresh.shape
    max_value, position = 0, (1, 1)
    y_start =1
    y_end = h-1
    for y in range(y_start,y_end):
        for x in range(1, w - 1):
            if y + template_h > h or x + template_w > w:
                continue
            block = target_canny[(y - 1):(y + template_h-1), (x - 1):(x + template_w-1)]
            value = (block * template_thresh).sum()
            if value > max_value:
                max_value = value
                position = (x, y)

                # show_cv(block, "block")
                # print(max_value)

    # # 轮廓填充展示
    # for ie in contour:
    #     ie[0][0] += x
    #     ie[0][1] += y
    #
    # target_copy = target.copy()
    # cv2.drawContours(target_copy, [contour], -1, (0, 255, 0), 1)
    # show_cv(target_copy, "target_copy")
    # print("耗费时间：",time.time()-time_start)


    return position # 最优解的左定点坐标
def match_dichotomy(target, template):
    """

    :param target:   搜索图原图
    :param template: 模版图原图
    :return:
    """

    target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
    template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    # w, h = templates.shape[::-1]

    res = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)

    run = 1

    # 使用二分法查找阈值的精确值
    L = 0
    R = 1
    offset_x = 0
    while run < 20:
        run += 1
        threshold = (R + L) / 2

        print("threshold",threshold)

        if threshold < 0:
            print("阈值小于0不合法！存在异常！")
            break

        loc = np.where(res >= threshold)

        if len(loc[1]) > 1:
            L += (R - L) / 2
        elif len(loc[1]) == 1:
            offset_x = loc[1][0]
            break
        elif len(loc[1]) < 1:
            R -= (R - L) / 2

    return offset_x,0
def preprocess_target(target):

    # show_cv(img)
    target_gaussian = cv2.GaussianBlur(target, (3, 3), 0)
    # show_cv(img_gaussian,"img_gaussian")

    target_gray = cv2.cvtColor(target_gaussian, cv2.COLOR_BGR2GRAY)

    # img_equ = cv2.equalizeHist(img_gray)
    # show_cv(img_equ,"img_equ")

    target_canny= cv2.Canny(target_gray, 100, 200)

    # lines = cv2.HoughLinesP(img_canny, 1, np.pi / 180, 30, minLineLength=2, maxLineGap=60)
    #
    # lines = lines[:, 0, :]  # shape变换 h,w,d = >h,d
    # img_canny_copy = img_canny.copy()
    # for x1, y1, x2, y2 in lines:
    #
    #     cv2.line(img_canny_copy, (x1, y1), (x2, y2), (0), 1)
    #
    #     # if abs(x2-x1)>30 and y1==y2:
    #     #     pass
    #     #     #保留
    #     # elif abs(y1-y2)>30 and x1==x2:
    #     #     pass
    #     #     # 保留
    #     # else:
    #     # cv2.line(img_copy, (x1, y1), (x2, y2), (0,255,0), 1)
    #
    # show_cv(img_canny_copy,"img_canny_copy_hough")

    # show_cv(img_canny,"img_canny")

    return target_canny
def preprocess_template(template):


    template_gaussian = cv2.GaussianBlur(template, (3, 3), 0)
    template_gray = cv2.cvtColor(template_gaussian, cv2.COLOR_BGR2GRAY)
    height = template.shape[0]
    width = template.shape[1]

    length_min = width
    if length_min>height:
        length_min = height

    # 部分场景下 二值化的图像提取轮廓效果并不好
    # _, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
    # show_cv(img_binary, "img_binary")

    # img_canny = cv2.Canny(img_gray, 100, 200)
    # show_cv(img_canny,"img_canny")

    contours, hierarchy = cv2.findContours(template_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    template_thresh = None
    x = 0
    y = 0
    contour = None

    for _contour in contours:
        # shape 335,1,2
        # 外接矩形
        rx, ry, rw, rh = cv2.boundingRect(_contour)

        # if w == 64 and h == 81:

        # if w ==83 and h ==83:
        # if w >75 and h >75:
        if rw >length_min*0.8 and rh >length_min*0.8:

            x = rx
            y = ry

            template_thresh = np.zeros((rh,rw,3))
            contour = _contour
            # print(x, y, w, h)
            # for point in contour:
            #     print("point",point,point[0][0],point[0][1])
            #     operator[point[0][0]-x][point[0][1]-y] = 1
            # 绘制外接矩形轮廓
            # img = cv2.rectangle(img_copy, (x, y), (x + w, y + h), (0, 255, 0), 2)
            # 绘制轮廓
            for ie in _contour:
                ie[0][0]-=rx
                ie[0][1]-=ry

            cv2.drawContours(template_thresh,[_contour],-1,(0,255,0),1)
            # epsilon = 0.5 * cv2.arcLength(contour,True)
            # approx = cv2.approxPolyDP(contour,epsilon,True)
            # cv2.drawContours(img_copy,[approx],-1,(0,255,0),2)



    # show_cv(template_gap, "template_gap1")

    template_thresh = template_thresh[:, :, 1]

    # show_cv(template_gap, "template_gap2")

    # # templates 原图canny检测，并霍夫检测去除干扰线
    # template_canny = cv2.Canny(cv2.cvtColor(templates, cv2.COLOR_BGR2GRAY), 100, 200)
    # show_cv(template_canny, "template_gap_canny")
    #
    # gap_lines = cv2.HoughLinesP(template_canny, 1, np.pi / 180, 30, minLineLength=2, maxLineGap=60)
    #
    # gap_lines = gap_lines[:, 0, :]  # shape变换 h,w,d = >h,d
    # template_copy = templates.copy()
    # for x1, y1, x2, y2 in gap_lines:
    #     cv2.line(template_copy, (x1, y1), (x2, y2), (0, 255, 0), 1)
    #
    # show_cv(template_copy, "template_copy")

    # template图 end

    return template_thresh,contour
def offset_calculate(target, template,method="dichotomy"):
    """
    :param target:   搜索 numpy像素图
    :param template: 模版 numpy 像素图
    :param method 支持的算法包含如下 "dichotomy","correlation"
    :return:
    """
    if type(target) == bytes:
        target = cv2.cvtColor(np.asarray(Image.open(BytesIO(target))), cv2.COLOR_RGB2BGR)
    if type(template) == bytes:
        template = cv2.cvtColor(np.asarray(Image.open(BytesIO(template))), cv2.COLOR_RGB2BGR)

    x, y = eval("match_%s" % method)(target, template)

    print("计算算法：%s"%method,"----","偏移x=%d,y=%d"%(x,y))


def read_image(url):
    if "http" in url:
        res = requests.get(url)
        img_pil = Image.open(BytesIO(res.content))
        # pil转cv2
        img = cv2.cvtColor(np.asarray(img_pil), cv2.COLOR_RGB2BGR)
    else:
        img = cv2.imread(url)

    return img
def show_image(img):
    cv2.imshow("image", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


if __name__ == '__main__':

    target = read_image("data/calcu_target.jpg")
    template = read_image("data/calcu_template.png")

    offset_calculate(target,template,method="correlation")



